/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "securec.h"
#include <stdint.h>
#include <sched.h>
#include <time.h>
#include "sle_iperf_common.h"
#include "sle_iperf_ssap_server.h"
#include <pthread.h>
#include <unistd.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stddef.h>

static uint16_t g_connectIdDelayLite = 0;
static uint16_t g_sle_server_conn_state = 0;
static uint16_t g_sendPackageSizeDelay = 0;
//static uint32_t kht_send_Seq = 0;
//static uint32_t kht_step = 0;
pthread_mutex_t tx_mutex_server;
static sle_kht_txrx_stat_t server_rx_stat = {0};  //总数据
static tx_context_t tx_ctx_server = {0};
static uint64_t sle_kht_this_pack_arrive_server = 0;
static uint64_t sle_kht_last_pack_arrive_server = 0;
static uint64_t sle_kht_max_jitter_server = 0;
static uint16_t g_SLE_KHT_IPERF_ONCE_PACK_NUM_SC = SLE_KHT_IPERF_ONCE_PACK_NUM;
static uint16_t g_SEND_STEP_SC = SEND_STEP;
static uint16_t g_ALL_SEND_PACKAGE_SC = ALL_SEND_PACKAGE;
static uint32_t g_IPERF_TIME_SC = IPERF_TIME;
static uint32_t g_iperf_long_time_delay_msSC = 0;

uint64_t sle_khtest_clock_gettime_us_lite(void)
{
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return ((uint64_t)ts.tv_sec * 1000000ULL + (uint64_t)ts.tv_nsec / 1000ULL);
}

uint64_t sle_kh_max_server(uint64_t numOne, uint64_t numTwo)
{
    if (numOne >= numTwo) {
        return numOne;
    } else {
        return numTwo;
    }
}

void SleSsapServerToolHalperDelay(void)
{
    printf("***SleSsapServerToolHalperDelay Command List****\r\n");
    for (uint16_t i = 0; i < g_ssapServerDelayCmdNum; i++) {
        printf("*     %02d - %-20s     *\r\n", i, g_ssapServerDelayCmdList[i].desc);
    }
    printf("*************************************\r\n");
}
static uint8_t g_serverIperfId = 255;
static uint8_t g_announceIperfId = 255;

SleErrorCode IperfStartAnnounce(void)
{
    char input[183];
    char announceData[200] = {'k','h','_','s','l','e','_','i','p','e','r','f','_','a','a','a',':', '\0'};
    strcat(announceData + 17, input);
    char responceData[200] = {'k','h','_','s','l','e','_','t','o','o','l','_','r','b','b','b',':', '\0'};
    strcat(responceData + 17, input);
    SleAnnounceData data = {
            .announceLength = strlen(announceData),
            .announceData = (uint8_t*)announceData,
            .responceLength = strlen(responceData),
            .responceData = (uint8_t*)responceData,
    };
    SleErrorCode ret = StartAnnounce(g_announceIperfId, &data, NULL);
    return ret;
}

#define OCTET_BIT_LEN 1600
char g_sle_property_value[OCTET_BIT_LEN] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
void TAutoConfigServer(void)
{
    uint32_t mtuIperf = (uint32_t)SleGetInputNumber("[iperf-test] enter autoConfigServer, input mtu:");
    //添加广播
    SleErrorCode ret = AddAnnounce(&g_announceIperfId);
    if(ret != SLE_NO_ERROR) {
        printf("[iperf-test] AddAnnounce failed(%hhu)\r\n", ret);
        return;
    }
    printf("[iperf-test] AddAnnounce OK, g_announceIperfId = %d \r\n", g_announceIperfId);

    //开始广播
    ret = IperfStartAnnounce();
    if(ret != SLE_NO_ERROR) {
        printf("[iperf-test] StartAnnounce failed(%hhu)\r\n", ret);
        return;
    }
    printf("[iperf-test] StartAnnounce OK, g_announceIperfId = %d \r\n", g_announceIperfId);

    //添加服务端
    SleUuid appUuid;
    memcpy(appUuid.uuid, "sleToolSsapsIpe", strlen("sleToolSsapsIpe"));
    appUuid.len = strlen("sleToolSsapsIpe");
    ret = AddSsapServer(&appUuid, &g_serverIperfId);
    if(ret != SLE_NO_ERROR) {
        printf("[iperf-test] AddSsapServer failed(%hhu)\r\n", ret);
        return;
    }
    printf("[iperf-test] AddSsapServer OK, serverId = %d \r\n", g_serverIperfId);

    //添加服务
    uint16_t serviceHandle;
    SleUuid serviceUuid;
    memcpy(serviceUuid.uuid, "sleToolServiceI", strlen("sleToolServiceI"));
    serviceUuid.len = strlen("sleToolServiceI");
    bool isPrimary = true;
    ret = AddService(g_serverIperfId, &serviceUuid, isPrimary, &serviceHandle);
    if(ret != SLE_NO_ERROR) {
        printf("[iperf-test] AddService failed(%hhu)\r\n", ret);
        return;
    }
    printf("[iperf-test] AddService OK, serverId = %d, serviceHandle = %d\r\n", g_serverIperfId, serviceHandle);

    //添加property
    SsapsPropertyParam param = {0};
    param.permissions = SSAP_PERMISSION_CAN_READ | SSAP_PERMISSION_CAN_WRITE;
    param.opIndication = SSAP_OPERATEIND_BIT_READ | SSAP_OPERATEIND_BIT_NOTIFY | SSAP_OPERATEIND_BIT_WRITE_NO_RSP;
    uint16_t propertyHandle;
    memcpy(param.uuid.uuid, "sleToolPropIper", strlen("sleToolPropIper"));
    param.uuid.len = strlen("sleToolPropIper");
    param.value = malloc(sizeof(g_sle_property_value));
    param.valueLen = sizeof(g_sle_property_value);
    if (param.value == NULL) {
        printf("SsapsPropertyParam value error");
        return;
    }
    if (memcpy_s(param.value, sizeof(g_sle_property_value), g_sle_property_value, sizeof(g_sle_property_value)) != 0) {
        free(param.value);
        printf("[uuid server] sle property mem cpy fail\r\n");
        return;
    }
    ret = AddProperty(g_serverIperfId, serviceHandle, &param, &propertyHandle);
    if(ret != SLE_NO_ERROR) {
        printf("[iperf-test] AddProperty failed(%hhu)\r\n", ret);
        return;
    }
    printf("[iperf-test] AddProperty OK, serverId = %d, serviceHandle = %d, propertyHandle = %d \r\n",
           g_serverIperfId, serviceHandle, propertyHandle);

    //添加descriptor
    uint8_t ntf_value[2] = {0x01, 0x0};
    uint16_t descHandle;
    SsapsDescriptorParam descriptor = {0};
    descriptor.permissions = SSAP_PERMISSION_CAN_READ | SSAP_PERMISSION_CAN_WRITE;
    descriptor.operateInd = SSAP_OPERATEIND_BIT_READ | SSAP_OPERATEIND_BIT_NOTIFY | SSAP_OPERATEIND_BIT_WRITE_NO_RSP;
    descriptor.value = malloc(sizeof(ntf_value));
    descriptor.valueLen = sizeof(ntf_value);
    if (descriptor.value == NULL) {
        printf("[uuid server] sle descriptor mem fail\r\n");
        free(param.value);
        return;
    }
    if (memcpy_s(descriptor.value, sizeof(ntf_value), ntf_value, sizeof(ntf_value)) != 0) {
        printf("[uuid server] sle descriptor mem cpy fail\r\n");
        free(param.value);
        free(descriptor.value);
        return;
    }
    ret = AddDescriptor(g_serverIperfId, serviceHandle, propertyHandle, &descriptor, &descHandle);
    if (ret != 0) {
        printf("[uuid server] sle uuid add descriptor fail, ret:%x\r\n", ret);
        free(param.value);
        free(descriptor.value);
        return;
    }
    printf("[iperf-test] AddDescriptor OK, serverId = %d, serviceHandle = %d, propertyHandle = %d, descHandle = %d \r\n",
           g_serverIperfId, serviceHandle, propertyHandle, descHandle);
    free(param.value);
    free(descriptor.value);

    //开始服务
    ret = StartService(g_serverIperfId, serviceHandle);
    if(ret != SLE_NO_ERROR) {
        printf("[iperf-test] StartService failed(%hhu)\r\n", ret);
        return;
    }
    printf("[iperf-test] StartService OK");

    //设置mtu
    SsapMtuInfo mtuInfo;
    mtuInfo.mtuSize = mtuIperf;
    ret = SetServerMtuInfo(g_serverIperfId, &mtuInfo);
    if(ret != SLE_NO_ERROR) {
        printf("[iperf-test] SetServerMtuInfo failed(%hhu)\r\n", ret);
        return;
    }
    printf("[iperf-test] SetServerMtuInfo OK, mtu = %d \r\n", mtuIperf);
    printf("[iperf-test] TAutoConfigServer end success \r\n");
}

void *TNotifyIndicateIperfDelay(void *arg)
{
    printf("[iperf-test] Enter TNotifyIndicateIperfDelay\r\n");
    uint32_t kht_send_Seq = 0;
    uint32_t kht_step = 0;
    uint8_t *data;
    data = (uint8_t *)malloc(g_sendPackageSizeDelay * sizeof(uint8_t));
    if (data == NULL) {
        printf("Failed to allocate memory.\n");
        return ((void *)0);
    }
    // 将分配的内存空间初始化为 0
    memset(data, 0, g_sendPackageSizeDelay * sizeof(uint8_t));
    sle_kht_msghdr *msghdr = (sle_kht_msghdr *)data;
    uint64_t begin_tv_us = 0, end_tv_us = 0;
    begin_tv_us = sle_khtest_clock_gettime_us_lite();
    uint32_t sle_kht_server_comm_seq = 0;
    uint64_t iperf_time = 0;
    uint64_t has_iperf = 0;
    printf("[iperf-test] g_sendPackageSizeDelay : %d \r\n", g_sendPackageSizeDelay);
    while (kht_step < g_SEND_STEP_SC) {
        while (g_sle_server_conn_state == SLE_CONNECT_CONNECTED_STATE && kht_send_Seq <= (g_ALL_SEND_PACKAGE_SC-1)) {

            msghdr->msgid = SLE_KHT_COMM_RX_PAYLOAD;
            msghdr->magic_num = SLE_KHT_MAGIC_NUM;
            msghdr->seqid = ++sle_kht_server_comm_seq;
            msghdr->length = g_sendPackageSizeDelay;

            SsapsNotifyParam param = {0};
            param.handle = 2;//propertyHandle
            param.type = 0;
            param.valueLen = g_sendPackageSizeDelay;
            param.value = data;

            if (g_iperf_long_time_delay_msSC > 0) {
                usleep(g_iperf_long_time_delay_msSC * 1000);
            }
            SleErrorCode ret = NotifyIndicate(0, g_connectIdDelayLite, &param);

            if(ret != SLE_NO_ERROR) {
                printf("[SleSsapServerTestTool] NotifyIndicate failed(%hhu)\r\n", ret);
                continue;
            }
            kht_send_Seq ++;
        }
        kht_step ++;
        kht_send_Seq = 0;
        if (g_IPERF_TIME_SC > 0) {
            iperf_time = sle_khtest_clock_gettime_us_lite();
            has_iperf = (iperf_time - begin_tv_us) / 1000000;
            if (has_iperf > g_IPERF_TIME_SC) {
                printf("[iperf-test] the iperf-time is end, time: %"PRIu64" ", has_iperf);
                break;
            }
        }

    }
    end_tv_us = sle_khtest_clock_gettime_us_lite();
    g_iperf_long_time_delay_msSC = 0;
    uint16_t server_end_retry = 0;
    while(server_end_retry < SEND_END_RETRY){
        server_end_retry++;
        msghdr->msgid = SLE_KHT_COMM_RX_END;
        msghdr->magic_num = SLE_KHT_MAGIC_NUM;
        msghdr->seqid = ++sle_kht_server_comm_seq;
        msghdr->length = g_sendPackageSizeDelay;

        SsapsNotifyParam param = {0};
        param.handle = 2;//propertyHandle
        param.type = 0;
        param.valueLen = g_sendPackageSizeDelay;
        param.value = data;
        SleErrorCode ret1 = NotifyIndicate(0, g_connectIdDelayLite, &param);
        if(ret1 != SLE_NO_ERROR) {
            printf("[SleSsapServerTestTool] NotifyIndicate failed(%hhu)\r\n", ret1);
        }
    }
    printf("[iperf-test] iperf server to client end, diff_us: %"PRIu64" , one_pack_size: %d, one_pack_send: %"PRIu64", "
           "send_package_one_step: %d, setps: %d, count-print: %d\n", (end_tv_us - begin_tv_us), g_sendPackageSizeDelay,
           (end_tv_us - begin_tv_us)/(g_ALL_SEND_PACKAGE_SC * g_SEND_STEP_SC), g_ALL_SEND_PACKAGE_SC, g_SEND_STEP_SC,
           g_SLE_KHT_IPERF_ONCE_PACK_NUM_SC);
    return ((void *)0);
}

void OnTRequestWriteDelayLiteCb(SleErrorCode errCode, uint8_t serverId,
                                uint16_t connectId, const SsapsReqWriteCbPara *writeCbPara)
{
    if (errCode){}
    if (serverId){}
    if (writeCbPara->valueLen < sizeof(sle_kht_msghdr)) {
        printf("[iperf-test] OnTRequestWriteCb (%d:%d)(%s:%d) %d\r\n", connectId, serverId
                , SsapPropertyTypeStr(writeCbPara->type), writeCbPara->handle, writeCbPara->valueLen);
        return;
    }

    sle_kht_msghdr *msghdr = (sle_kht_msghdr *)writeCbPara->value;
    if (msghdr->magic_num != SLE_KHT_MAGIC_NUM) {
        printf("[iperf-test] OnTRequestWriteCb (%d:%d)(%s:%d) %d\r\n", connectId, serverId
                , SsapPropertyTypeStr(writeCbPara->type), writeCbPara->handle, writeCbPara->valueLen);
        return;
    }

    //打流
    if (msghdr->msgid == SLE_KHT_COMM_CLIENT_REQ_SERVER){
        g_connectIdDelayLite = connectId;
        g_sendPackageSizeDelay = msghdr->length;
        g_SEND_STEP_SC = msghdr->sendstep;
        g_ALL_SEND_PACKAGE_SC = msghdr->allsendpackage;
        g_SLE_KHT_IPERF_ONCE_PACK_NUM_SC = msghdr->oncecount;
        g_IPERF_TIME_SC = msghdr->iperftime;
        g_iperf_long_time_delay_msSC = msghdr->iperfdelaytime;
        printf("[iperf-test] receive SLE_KHT_COMM_RX_PAYLOAD, connectId: %d, send pack_len: %d, send %d packages, "
               "step: %d, oncecount: %d, iperf_time: %d, delay_iperf: %d \r\n", g_connectIdDelayLite, g_sendPackageSizeDelay,
               g_ALL_SEND_PACKAGE_SC, g_SEND_STEP_SC, g_SLE_KHT_IPERF_ONCE_PACK_NUM_SC, g_IPERF_TIME_SC, g_iperf_long_time_delay_msSC);

        pthread_t new_thread;
        int rc;
        // 创建新线程
        rc = pthread_create(&new_thread, NULL, TNotifyIndicateIperfDelay, NULL);
        if (rc) {
            printf("Error: unable to create thread, %d\n", rc);
        }
    }

    //时延
    if (msghdr->msgid == COUNT_TIME_DELAY_ID) {
        g_connectIdDelayLite = connectId;
        g_sendPackageSizeDelay = writeCbPara->valueLen;
        printf("[iperf-test] receive time delayCOUNT_TIME_DELAY_ID,connectId:%d, data_len:%d \r\n",
               g_connectIdDelayLite, g_sendPackageSizeDelay);
        uint8_t *data_delay;
        data_delay = (uint8_t *)malloc(g_sendPackageSizeDelay * sizeof(uint8_t));
        if (data_delay == NULL) {
            printf("Failed to allocate memory.\n");
            return;
        }
        // 将分配的内存空间初始化为 0
        memset(data_delay, 0, g_sendPackageSizeDelay * sizeof(uint8_t));
        sle_kht_msghdr *msghdr_iperf = (sle_kht_msghdr *)data_delay;

        msghdr_iperf->msgid = COUNT_TIME_DELAY_ID;
        msghdr_iperf->magic_num = SLE_KHT_MAGIC_NUM;
        msghdr_iperf->length = g_sendPackageSizeDelay;

        SsapsNotifyParam param = {0};
        param.handle = 2; //propertyHandle
        param.type = 0;
        param.valueLen = g_sendPackageSizeDelay;
        param.value = data_delay;

        SleErrorCode ret = NotifyIndicate(0, g_connectIdDelayLite, &param);

        if(ret != SLE_NO_ERROR) {
            printf("[SleSsapServerTestTool] NotifyIndicate failed(%hhu)\r\n", ret);
        }
    }

    float diff_us;
    pthread_mutex_lock(&tx_mutex_server);
    switch (msghdr->msgid) {
        case SLE_KHT_COMM_CLIENT_IPERF_TO_SERVER:
            // 统计流量
            if (0 == server_rx_stat.total_count) {
                server_rx_stat.begin_tv_us = sle_khtest_clock_gettime_us_lite();
                server_rx_stat.total_drops = 0;
                server_rx_stat.total_bytes = writeCbPara->valueLen;
                sle_kht_this_pack_arrive_server = server_rx_stat.begin_tv_us;
                sle_kht_last_pack_arrive_server = sle_khtest_clock_gettime_us_lite();
                sle_kht_max_jitter_server = 0;
            } else {
                //client_rx_stat.seq_stop = msghdr->seqid;
                server_rx_stat.total_bytes += writeCbPara->valueLen;
                sle_kht_this_pack_arrive_server = sle_khtest_clock_gettime_us_lite();
                uint64_t diff_jitter = sle_kht_this_pack_arrive_server - sle_kht_last_pack_arrive_server;
                sle_kht_max_jitter_server = sle_kh_max_server(sle_kht_max_jitter_server, diff_jitter);
                sle_kht_last_pack_arrive_server = sle_kht_this_pack_arrive_server;
            }

            if (tx_ctx_server.start_seq == 0) {
                tx_ctx_server.start_seq = msghdr->seqid; // 记录本轮统计第一个包的序列号
                tx_ctx_server.last_seq = msghdr->seqid;
            } else {
                do {
                    if (msghdr->seqid < tx_ctx_server.start_seq) {
                        break; // 旧的报文
                    }

                    //msghdr->seqid > tx_ctx->start_seq
                    if (msghdr->seqid > tx_ctx_server.last_seq) {
                        if ((msghdr->seqid - tx_ctx_server.last_seq) > 1) {
                            // 乱序丢包
                            server_rx_stat.total_drops += (msghdr->seqid - tx_ctx_server.last_seq - 1);
                        }
                        tx_ctx_server.last_seq = msghdr->seqid;
                        break;
                    }

                    if (msghdr->seqid == tx_ctx_server.last_seq) {
                        pthread_mutex_unlock(&tx_mutex_server);
                        return; // 重复的包
                    }

                    if (msghdr->seqid < tx_ctx_server.last_seq) {
                        // 前面的乱序包, 补偿
                        if (server_rx_stat.total_drops > 0) {
                            server_rx_stat.total_drops --;
                        }
                    }
                } while (0);
            }

            server_rx_stat.total_count += 1;
//            printf("[iperf-test] seqid: %d, data->dataLength: %d\r\n", msghdr->seqid, data->dataLength);
            if ((server_rx_stat.total_count + server_rx_stat.total_drops) >= msghdr->oncecount) {
                server_rx_stat.end_tv_us = sle_khtest_clock_gettime_us_lite();
                diff_us = (float)(server_rx_stat.end_tv_us - server_rx_stat.begin_tv_us);
                diff_us /= 1000; // =ms
                if ((int)diff_us == 0) diff_us = 1;

                double rate_iperf = (double)((server_rx_stat.total_bytes*8*1024)/diff_us);

                printf("[iperf-test] one_pack_size: %d, rate_iperf: %.3lfbps, cost_time_ms: %.3lfms, "
                       "this_drop %u, this_receive %u, this_pack %u\r\n", writeCbPara->valueLen, rate_iperf, diff_us,
                       server_rx_stat.total_drops, server_rx_stat.total_count,
                       (server_rx_stat.total_drops + server_rx_stat.total_count));

                server_rx_stat.total_count = 0;
                server_rx_stat.total_bytes = 0;
                server_rx_stat.total_drops = 0;
            }
            break;

        case SLE_KHT_COMM_RX_END:
            if (server_rx_stat.total_bytes > 0){
                printf("[iperf-test] recerve end\r\n");
                server_rx_stat.total_count = 0;
                server_rx_stat.total_bytes = 0;
                server_rx_stat.total_drops = 0;
            }
        default:
            break;
    }
    pthread_mutex_unlock(&tx_mutex_server);
}

void *TStartAnnounceIperf(void *arg)
{
    SleErrorCode ret = IperfStartAnnounce();
    if(ret != SLE_NO_ERROR) {
        printf("[iperf-test] device disconnect, retry StartAnnounce failed(%hhu)\r\n", ret);
        return ((void*)0);
    }
    printf("[iperf-test] device disconnect, retry StartAnnounce OK, g_announceIperfId = %d \r\n", g_announceIperfId);
    return ((void*)0);
}

void OnSleTConnStateChangeDelayLiteCb(uint16_t connectId, const SleDeviceAddress *addr
        , SleConnectState connState, SlePairState pairState, SleDisConnectReason discReason)
{
    if (addr){}
    if (pairState){}
    if (discReason){}
    g_sle_server_conn_state = connState;
    if (g_sle_server_conn_state == SLE_CONNECT_DISCONNECTED_STATE && g_announceIperfId != 255 && g_serverIperfId != 255) {
        pthread_t new_thread;
        int rc;
        // 创建新线程
        rc = pthread_create(&new_thread, NULL, TStartAnnounceIperf, NULL);
        if (rc) {
            printf("Error: unable to create thread, %d\n", rc);
        }
    }
}

#ifdef __cplusplus
}
#endif // __cplusplus